package Verifier.Marshal;

import Verifier.GeneralUtils;
import Verifier.ArithmeticSystem.ArithmeticConvertor;
import Verifier.ArithmeticSystem.Group;
import Verifier.ArithmeticSystem.ModularGroup;
import Verifier.ByteTree.ByteTree;
import Verifier.ByteTree.ByteTreeElement;
import Verifier.ByteTree.Leaf;
import Verifier.ByteTree.Node;

/** 
 * This class contains service functions to help representing objects as ByteTrees (Marshaling),
 * and also to help transform a ByteTree of an object to its corresponding class object (Unmarshaling).
 * 
 * @author Yoni Sapir
 *
 */
public class MarshalParser {
	
	/**
     * This method transforms the given Group into ByteTree in the appropriate form.
     * 
     * @param group - The Group to be transformed to ByteTree.
     * @return The ByteTree, representing the given Group.
     * @throws Exception upon misusing other methods.
     * 
     */
	public static ByteTree Marshal(Group group) throws Exception {
		if (!(group instanceof ModularGroup)) {
			return (null);
		}
		
		ByteTree bt = ArithmeticConvertor.ToByteTree((ModularGroup)group);
		
		String str = "verificatum.arithm.ModPGroup";
		byte[] byte_str = GeneralUtils.convertStringToBytes(str);
		Leaf leaf = new Leaf(byte_str, null);
		
		Node node = new Node(null);
		node.addElement(leaf);
		node.addElement(bt.getFirstByteTreeElement());
		return (new ByteTree(node));
	}
	
	/**
     * An instance of the corresponding class that was stated within the ByteTree is returned.
     * null is returned if the stated class in the ByteTree is not the class ModPGroup.
     * 
     * @param bt - The ByteTree that represents an object that should be created.
     * @return The Group, represented by the given ByteTree.
     * @throws Exception upon wrong input form, and upon wrong Group name given in the input.
     * 
     */
	public static Group Unmarshal(ByteTree bt) throws Exception {
		ByteTreeElement bte = bt.getFirstByteTreeElement();
		if (!(bte instanceof Node)) {
			throw new Exception("Incorrect form of input: Not a node!");
		}
		
		Node node = (Node)bte;
		if (2 != node.getDataLength()) {
			throw new Exception("Incorrect form of input: Number of child nodes is incorrect!");
		}
		
		ByteTreeElement temp = node.getChild(0);
		if (!(temp instanceof Leaf)) {
			throw new Exception("Incorrect form of input: First child is not a leaf!");
		}
		
		Leaf leaf = (Leaf)temp;
		byte[] byte_temp = leaf.getDataByteArray();
		String str = GeneralUtils.convertBytesToString(byte_temp);
		
		if (0 != str.compareTo("verificatum.arithm.ModPGroup")) {
			throw new Exception("Incorrect form of input: Unexpected string!");
		}
		
		ModularGroup MG = ArithmeticConvertor.ToModularGroup(new ByteTree(node.getChild(1)));
		return MG;
	}
}
